package com.lqian.concurrenthashmap_cas;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*
 * @description: 并发的字符串统计
 * 统计每个接口访问的次数。一个接口对应一个url，也就是一个字符串，每调用一次对其进行加一处理。
 * 可能出现的问题主要有三个：
        多线程访问，需要选择合适的并发容器
        分布式下多个实例统计接口流量需要共享内存
        流量统计应该尽可能不损耗服务器性能
 * @author: Melody_LQ
 * @date: 2022/11/15 9:16 AM
 **/
public class CounterStringDemo01 {
    private final Map<String, Long> urlCounter = new ConcurrentHashMap<>();

    //接口调用次数+1
    public long increase(String url) {
        Long oldValue = urlCounter.get(url);
        Long newValue = (oldValue == null) ? 1L : oldValue + 1;
        urlCounter.put(url, newValue);
        return newValue;
    }
    //获取调用次数
    public Long getCount(String url){
        return urlCounter.get(url);
    }


    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(10);
        final CounterStringDemo01 counterDemo = new CounterStringDemo01();
        int callTime = 100000;
        final String url = "http://localhost:8080/hello";
        CountDownLatch countDownLatch = new CountDownLatch(callTime);

        //模拟并发情况下的接口调用统计
        for(int i=0;i<callTime;i++){
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    counterDemo.increase(url);
                    countDownLatch.countDown();
                }
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executor.shutdown();
        //等待所有线程统计完成后输出调用次数

        System.out.println("调用次数："+counterDemo.getCount(url));
    }

    /*
    *  调用次数：95909
    *  ConcurrentHashMap能保证的是每一个操作(put,get,delete...)单次操作本身是线程安全的，
    *  但是我们的increase方法，对ConcurrentHashMap的操作是一个组合，先get再put，所以多个线程的操作出现了覆盖
    *  如果对整个increase方法加锁，那么又违背了我们使用并发容器的初衷，因为锁的开销很大。
    *
    *
    * */
}
